Dynamic Programming / Counting Tilings

#include <bits/stdc++.h>
using namespace std;

using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;
using isize = ptrdiff_t;
using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using usize = size_t;
using f32 = float_t;
using f64 = double_t;

inline constexpr i32 Modulus = 1e9 + 7;

int main(void)
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    u16 n, m;
    cin >> n >> m;

    u16 stateLimit = 1 << n;
    auto dp = vector<vector<u32>>(m + 1, vector<u32>(stateLimit, 0));
    dp[0][0] = 1;

    for (u16 column = 1; column <= m; column += 1)
    {
        for (u16 previousState = 0; previousState < stateLimit; previousState += 1)
        {
            u32 numberOfWays = dp[column - 1][previousState];
            if (numberOfWays == 0)
            {
                continue;
            }

            stack<pair<u16, u16>> possibleTilings;
            possibleTilings.emplace(0, 0);

            while (!possibleTilings.empty())
            {
                auto [row, currentState] = possibleTilings.top();
                possibleTilings.pop();

                if (row == n)
                {
                    dp[column][currentState] = (dp[column][currentState] + numberOfWays) % Modulus;
                    continue;
                }

                if (previousState & (1 << row))
                {
                    possibleTilings.emplace(row + 1, currentState);
                    continue;
                }

                possibleTilings.emplace(row + 1, currentState | (1 << row));
                if (row + 1 < n && (previousState & (1 << (row + 1))) == 0)
                {
                    possibleTilings.emplace(row + 2, currentState);
                }
            }
        }
    }

    cout << dp[m][0];

    return 0;
}